﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Fierce.Utility.Helper
{
    /// <summary>
    /// 序列化 JSON 工具
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 任意对象序列化
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="retain">保留属性</param>
        /// <param name="ignore">忽略属性</param>
        /// <param name="turns">要转换的属性</param>
        /// <param name="dateTimeFormate">日期格式</param>
        /// <returns>返回数据</returns>
        public static string Serialize(object obj,
            string[] retain = null,
            string[] ignore = null,
            IDictionary<string, string> turns = null,
            string dateTimeFormate = "yyyy'-'MM'-'dd' 'HH':'mm':'ss")
        {
            var settings = new JsonSerializerSettings();

            if (retain != null || ignore != null || turns != null)
            {
                // 设置序列化解析器
                settings.ContractResolver = new CustomContractResolver(retain, ignore, turns);
            }

            // 设置序列化时间格式
            IsoDateTimeConverter timeConverter = new IsoDateTimeConverter();
            timeConverter.DateTimeFormat = dateTimeFormate;
            settings.Converters.Add(timeConverter);

            return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
        }

        /// <summary>
        /// 表格序列化
        /// </summary>
        /// <param name="rows">数据总行数</param>
        /// <param name="obj">对象</param>
        /// <param name="retain">保留属性</param>
        /// <param name="ignore">忽略属性</param>
        /// <param name="turns">要转换的属性</param>
        /// <param name="dateTimeFormate">日期格式</param>
        /// <returns>返回数据</returns>
        public static string Grid(object obj, int count,
            string[] retain = null,
            string[] ignore = null,
            IDictionary<string, string> turns = null,
            string dateTimeFormate = "yyyy'-'MM'-'dd' 'HH':'mm':'ss")
        {
            return Serialize(new { total = count, rows = obj }, retain, ignore, turns, dateTimeFormate);
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T">要返回的类型</typeparam>
        /// <param name="obj">数据</param>
        /// <returns>返回对象</returns>
        public static T Deserialize<T>(string obj)
        {
            var settings = new JsonSerializerSettings();

            settings.NullValueHandling = NullValueHandling.Ignore;
            settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
            settings.MissingMemberHandling = MissingMemberHandling.Ignore;
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

            return JsonConvert.DeserializeObject<T>(obj, settings);
        }

        /// <summary>
        /// 自定义序列化解析器
        /// </summary>
        public class CustomContractResolver : DefaultContractResolver
        {
            string[] retain = null;
            string[] ignore = null;
            IDictionary<string, string> turns = null;

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="retain">保留属性</param>
            /// <param name="ignore">忽略属性</param>
            /// <param name="turns">要转换的属性</param>
            public CustomContractResolver(string[] retain = null, string[] ignore = null, IDictionary<string, string> turns = null)
            {
                // 指定要序列化属性的清单
                this.retain = retain;
                // 指定要忽略属性的清单
                this.ignore = ignore;
                // 指定要转换名称属性的清单
                this.turns = turns;
            }

            /// <summary>
            /// 重写属性创建函数
            /// </summary>
            /// <param name="type">对象类型</param>
            /// <param name="memberSerialization">成员序列化对象</param>
            /// <returns>成员属性集合</returns>
            protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                List<JsonProperty> list = base.CreateProperties(type, memberSerialization).ToList();

                if (retain != null)
                {
                    // 只保留清单有列出的属性
                    list = list.Where(p => retain.Contains(p.PropertyName)).ToList();
                }

                if (ignore != null)
                {
                    // 只保留清单有列出的属性
                    list = list.Where(p => !ignore.Contains(p.PropertyName)).ToList();
                }

                if (turns != null)
                {
                    // 修改需要修改名称的属性
                    foreach (var turn in turns)
                    {
                        list.ForEach(new Action<JsonProperty>((m) =>
                        {
                            if (m.PropertyName == turn.Key)
                            {
                                m.PropertyName = turn.Value;
                            }
                        }));
                    }
                }

                return list;
            }
        }
    }
}
